package com.lili.collection.core.runner.result;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.map.MapUtil;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 描述: 错误输出记录日志数据
 *
 * @date:2023/3/30 14:53
 * @author:lili
 */
@Data
public class ErrOutputData implements Serializable {
    private static final long serialVersionUID = -2305460316535812442L;
    public static final int DEFAULT_ERROR_SIZE = 10;

    /**
     * 错误行号
     */
    @JSONField(name="错误行序号")
    private int errorRowOrder;

    /**
     * INSERT
     * QUERY
     */
    @JSONField(name="日志类型")
    private String type;

    /**
     * 插入SQL语句
     */
    @JSONField(name="执行SQL")
    private String sql;

    /**
     * 总数据量大小
     */
    @JSONField(name="总数据量大小")
    private int totalSize;

    /**
     * 当前批量大小
     */
    @JSONField(name="当前批量大小")
    private int batchSize;

    /**
     * 当前批量位置
     */
    @JSONField(name="批量索引下标")
    private int batchIndex;

    /**
     * 错误消息
     */
    @JSONField(name="错误消息")
    private String errorMessage;

    /**
     * 偏移量删除数量
     */
    @JSONField(name="删除偏移数")
    private int deleteOffsetNum;

    /**
     * 是否首批次错误
     */
    @JSONField(name="是否首批错误")
    private boolean firstBatchError = false;

    /**
     * 错误记录大小
     */
    @JSONField(name="最大错误记录数")
    private int maxErrorSize = DEFAULT_ERROR_SIZE;

    /**
     * 详情属性数据
     */
    @JSONField(name="错误样例详情")
    private List<ErrorDetail> errorValueDetailList = new ArrayList<>();

    /**
     * 错误数统计
     */
    @JSONField(name="错误类型统计")
    private Map<String, Integer> errorStatistics = new HashMap<>();

    /**
     * 错误总数
     */
    @JSONField(name="错误总数")
    private int errorTotal;

    /**
     * 是否开启事务
     */
    @JSONField(name="事务支持")
    private boolean transaction;

    /**
     * 限制数统计量为100
     * @return
     */
    private boolean noPutErrInfo(){
        return errorStatistics.size() > 100;
    }

    /**
     * 自增错误数
     */
    public void incrementErrorTotal() {
        this.errorTotal++;
    }

    /**
     * 添加错误数
     * @param errorCount 具体错误数
     */
    public void addErrorTotal(int errorCount) {
        this.errorTotal += errorCount;
    }

    /**
     * 添加错误类型
     * @param errorInfo 错误值
     */
    public void putErrorInfo(String errorInfo){
        if(noPutErrInfo()){
            return;
        }
        Integer errorNum = errorStatistics.get(errorInfo);
        if(errorNum==null){
            errorStatistics.put(errorInfo,1);
        }else {
            errorStatistics.put(errorInfo,errorNum+1);
        }
    }

    /**
     * 合并统计
     * @param mergeErrStatisticMap
     */
    public void mergeErrorInfo(Map<String, Integer> mergeErrStatisticMap){
        if(MapUtil.isEmpty(mergeErrStatisticMap) || noPutErrInfo()){
            return;
        }
        for (String errorInfo : mergeErrStatisticMap.keySet()) {
            Integer errorNum = mergeErrStatisticMap.get(errorInfo);
            if(noPutErrInfo()){
                break;
            }
            Integer originalErrorNum = errorStatistics.get(errorInfo);
            if(originalErrorNum==null){
                errorStatistics.put(errorInfo,errorNum);
            }else {
                errorStatistics.put(errorInfo,originalErrorNum+errorNum);
            }
        }
    }

    /**
     * 清空详细记录
     */
    public void clear() {
        errorValueDetailList.clear();
    }

    /**
     * 判断是否能放置详情
     * @return
     */
    public boolean canPutDown() {
        return maxErrorSize > this.errorValueDetailList.size();
    }

    /**
     * 添加错误详情
     * @param errorValueDetail
     */
    public void addErrorValueDetail(ErrorDetail errorValueDetail) {
        if (this.errorValueDetailList.size() >= maxErrorSize) {
            return;
        }
        this.errorValueDetailList.add(errorValueDetail);
    }

    /**
     * 合并错误详情
     * @param errorValueDetail
     */
    public void addAllErrorValueDetails(List<ErrorDetail> errorValueDetail) {
        if (CollectionUtil.isEmpty(errorValueDetail)) {
            return;
        }
        if (this.errorValueDetailList.size() > maxErrorSize) {
            return;
        }
        int remainingSize = maxErrorSize - this.errorValueDetailList.size();
        if (remainingSize == 0) {
            return;
        }
        int subSize = errorValueDetail.size() > remainingSize ? remainingSize : errorValueDetail.size();
        this.errorValueDetailList.addAll(errorValueDetail.subList(0, subSize));
    }
}